home *** CD-ROM | disk | FTP | other *** search
/ AppleScript - The Beta Release / AppleScript - The Beta Release.iso / Documentation / develop / Better Apple Event Coding / Code Samples / TEDocument.cp < prev    next >
Encoding:
Text File  |  1992-10-16  |  38.9 KB  |  1,559 lines  |  [TEXT/MPS ]

  1. /*------------------------------------------------------------------------------------------
  2.  
  3.     Program:    CPlusTESample 2.0AE
  4.     File:        TEDocument.cp
  5.     Uses:       TEDocument.h
  6.                 TESample.h
  7.  
  8.     by Andrew Shebanow
  9.     of Apple Macintosh Developer Technical Support
  10.     with modifications by Eric Berdahl
  11.  
  12.     Copyright © 1989-1990 Apple Computer, Inc.
  13.     Copyright © 1992 Eric Berdahl
  14.     All rights reserved.
  15.  
  16. ------------------------------------------------------------------------------------------*/
  17.  
  18. // Mac Includes
  19. #ifndef __TYPES__
  20. #include <Types.h>
  21. #endif
  22. #ifndef __QUICKDRAW__
  23. #include <QuickDraw.h>
  24. #endif
  25. #ifndef __FONTS__
  26. #include <Fonts.h>
  27. #endif
  28. #ifndef __EVENTS__
  29. #include <Events.h>
  30. #endif
  31. #ifndef __CONTROLS__
  32. #include <Controls.h>
  33. #endif
  34. #ifndef __WINDOWS__
  35. #include <Windows.h>
  36. #endif
  37. #ifndef __MENUS__
  38. #include <Menus.h>
  39. #endif
  40. #ifndef __TEXTEDIT__
  41. #include <TextEdit.h>
  42. #endif
  43. #ifndef __DIALOGS__
  44. #include <Dialogs.h>
  45. #endif
  46. #ifndef __DESK__
  47. #include <Desk.h>
  48. #endif
  49. #ifndef __SCRAP__
  50. #include <Scrap.h>
  51. #endif
  52. #ifndef __TOOLUTILS__
  53. #include <ToolUtils.h>
  54. #endif
  55. #ifndef __MEMORY__
  56. #include <Memory.h>
  57. #endif
  58. #ifndef __SEGLOAD__
  59. #include <SegLoad.h>
  60. #endif
  61. #ifndef __FILES__
  62. #include <Files.h>
  63. #endif
  64. #ifndef __OSUTILS__
  65. #include <OSUtils.h>
  66. #endif
  67. #ifndef __TRAPS__
  68. #include <Traps.h>
  69. #endif
  70. #ifndef __PACKAGES__
  71. #include <Packages.h>
  72. #endif
  73. #ifndef __ERRORS__
  74. #include <Errors.h>
  75. #endif
  76.  
  77. #ifndef __AEOBJECTS__
  78. #include "AEObjects.h"
  79. #endif
  80. #ifndef __AEREGISTRY__
  81. #include "AERegistry.h"
  82. #endif
  83. #ifndef __TEDOCUMENT__
  84. #include "TEDocument.h"
  85. #endif
  86. #ifndef __TESAMPLE__
  87. #include "TESample.h"
  88. #endif
  89.  
  90. extern "C" {
  91.     // prototypes for functions that can't belong to TEDocument, but
  92.     // which are closely tied into our documents
  93.     pascal ClikLoopProcPtr GetOldClikLoop();
  94.     pascal void PascalClikLoop();
  95.     void CommonAction(ControlHandle control,short* amount);
  96.     pascal void VActionProc(ControlHandle control,short part);
  97.     pascal void HActionProc(ControlHandle control,short part);
  98.     // this routine is written in Assembler, since it needs to tweak registers
  99.     pascal void ASMCLIKLOOP();
  100. };
  101.  
  102. // kTextMargin is the number of pixels we leave blank at the edge of the window.
  103. const short kTextMargin = 2;
  104.  
  105. // kMaxDocWidth is an arbitrary number used to specify the width of the TERec's
  106. // destination rectangle so that word wrap and horizontal scrolling can be
  107. // demonstrated.
  108. const short    kMaxDocWidth = 576;
  109.  
  110. // kMinDocDim is used to limit the minimum dimension of a window when GrowWindow
  111. // is called.
  112. const short    kMinDocDim = 64;
  113.  
  114. // kMaxTELength is an arbitrary number used to limit the length of text in the TERec
  115. // so that various errors won't occur from too many characters being in the text.
  116. const short    kMaxTELength = 32000;
  117.  
  118. // kControlInvisible is used the same way to 'turn on' the control.
  119. const short kControlVisible = 0xFF;
  120.  
  121. // ScrollBarAdjust, GrowBoxAdjust, and ScrollBar width are used in calculating
  122. // values for control positioning and sizing.
  123. const short kScrollbarAdjust = 15;
  124. const short kGrowboxAdjust = 15;
  125. const short kScrollbarWidth = 16;
  126.  
  127. // kTESlop provides some extra security when pre-flighting edit commands.
  128. const short kTESlop = 1024;
  129.  
  130. // kScrollTweek compensates for off-by-one requirements of the scrollbars
  131. // to have borders coincide with the growbox.
  132. const short kScrollTweek = 2;
  133.  
  134. // kCrChar is used to match with a carriage return when calculating the
  135. // number of lines in the TextEdit record. kDelChar is used to check for
  136. // delete in keyDowns.
  137. const short kCrChar = 13;
  138. const short kDelChar = 8;
  139.  
  140. //--------------------------------------------------------------------------------
  141. // TWindowName
  142. //--------------------------------------------------------------------------------
  143.  
  144. class TWindowName : public MAppleObject
  145. {
  146. public:
  147.     TWindowName(TEDocument* itsDocument);
  148.  
  149.     virtual void DoAppleEvent(const AppleEvent& message, AppleEvent& reply, long refCon);
  150.     virtual DescType GetAppleClass() const;
  151.  
  152.     virtual void DoAppleGetData(const AppleEvent& message, AppleEvent& reply);
  153.     virtual void DoAppleSetData(const AppleEvent& message, AppleEvent& reply);
  154. private:
  155.     TWindowName();
  156.  
  157.     TEDocument*    fDocument;
  158. };
  159.  
  160.  
  161. TWindowName::TWindowName(TEDocument* itsDocument)
  162. {
  163.     fDocument = itsDocument;
  164. }
  165.  
  166.  
  167. void TWindowName::DoAppleEvent(const AppleEvent& message, AppleEvent& reply, long refCon)
  168. {
  169.     switch (refCon)
  170.     {
  171.     case cSetData:
  172.         this->DoAppleSetData(message, reply);
  173.         break;
  174.     case cGetData:
  175.         this->DoAppleGetData(message, reply);
  176.         break;
  177.     default:
  178.         MAppleObject::DoAppleEvent(message, reply, refCon);
  179.         break;
  180.     }
  181. }
  182.  
  183.  
  184. DescType TWindowName::GetAppleClass() const
  185. {
  186.     return typeText;
  187. }
  188.  
  189.  
  190. void TWindowName::DoAppleGetData(const AppleEvent& message, AppleEvent& reply)
  191. {
  192.     MAppleObject::GotRequiredParameters(message);
  193.  
  194.     // Get the name of the window
  195.     Str255    name;
  196.     GetWTitle(fDocument->GetDocWindow(), name);
  197.  
  198.     // Pack the text into a descriptor
  199.     AEDesc    nameDesc;
  200.     FailOSErr(AECreateDesc(typeText, (Ptr) &name[1], name[0], &nameDesc));
  201.  
  202.     // package the reply
  203.     OSErr theErr = AEPutParamDesc(&reply, keyDirectObject, &nameDesc);
  204.  
  205.     // dispose of the descriptor we created and check the reply from
  206.     // packaging the reply
  207.     OSErr ignoreErr = AEDisposeDesc(&nameDesc);
  208.     FailOSErr(theErr);
  209. }
  210.  
  211.  
  212. void TWindowName::DoAppleSetData(const AppleEvent& message, AppleEvent& /* reply */)
  213. {
  214.     DescType    returnedType;
  215.     Str255        theName;
  216.     Size        actualSize;
  217.     FailOSErr(AEGetParamPtr(&message, keyAETheData, typeText, &returnedType,
  218.                             (Ptr) &theName[1], 255, &actualSize));
  219.     if (actualSize > 255)
  220.         actualSize = 255;
  221.     theName[0] = (unsigned char) actualSize;
  222.  
  223.     MAppleObject::GotRequiredParameters(message);
  224.  
  225.     SetWTitle(fDocument->GetDocWindow(), theName);
  226. }
  227.  
  228.  
  229. //--------------------------------------------------------------------------------
  230. // TWindowPosition
  231. //--------------------------------------------------------------------------------
  232.  
  233. class TWindowPosition : public MAppleObject
  234. {
  235. public:
  236.     TWindowPosition(TEDocument* itsDocument);
  237.  
  238.     virtual void DoAppleEvent(const AppleEvent& message, AppleEvent& reply, long refCon);
  239.     virtual DescType GetAppleClass() const;
  240.  
  241.     virtual void DoAppleGetData(const AppleEvent& message, AppleEvent& reply);
  242.     virtual void DoAppleSetData(const AppleEvent& message, AppleEvent& reply);
  243. private:
  244.     TWindowPosition();
  245.  
  246.     TEDocument*    fDocument;
  247. };
  248.  
  249.  
  250. TWindowPosition::TWindowPosition(TEDocument* itsDocument)
  251. {
  252.     fDocument = itsDocument;
  253. }
  254.  
  255.  
  256. void TWindowPosition::DoAppleEvent(const AppleEvent& message, AppleEvent& reply, long refCon)
  257. {
  258.     switch (refCon)
  259.     {
  260.     case cSetData:
  261.         this->DoAppleSetData(message, reply);
  262.         break;
  263.     case cGetData:
  264.         this->DoAppleGetData(message, reply);
  265.         break;
  266.     default:
  267.         MAppleObject::DoAppleEvent(message, reply, refCon);
  268.         break;
  269.     }
  270. }
  271.  
  272.  
  273. DescType TWindowPosition::GetAppleClass() const
  274. {
  275.     return cQDPoint;
  276. }
  277.  
  278.  
  279. void TWindowPosition::DoAppleGetData(const AppleEvent& message, AppleEvent& reply)
  280. {
  281.     MAppleObject::GotRequiredParameters(message);
  282.  
  283.     // Get the position of the window (topLeft of the bounds)
  284.     Rect    myBounds = (*WindowPeek(fDocument->GetDocWindow())->strucRgn)->rgnBBox;
  285.     Point    myPosition;
  286.     myPosition.v = myBounds.top;
  287.     myPosition.h = myBounds.left;
  288.  
  289.     // Pack the position into a descriptor
  290.     AEDesc    posDesc;
  291.     FailOSErr(AECreateDesc(typeQDPoint, (Ptr) &myPosition, sizeof(myPosition), &posDesc));
  292.  
  293.     // package the reply
  294.     OSErr theErr = AEPutParamDesc(&reply, keyDirectObject, &posDesc);
  295.  
  296.     // dispose of the descriptor we created and check the reply from
  297.     // packaging the reply
  298.     OSErr ignoreErr = AEDisposeDesc(&posDesc);
  299.     FailOSErr(theErr);
  300. }
  301.  
  302.  
  303. void TWindowPosition::DoAppleSetData(const AppleEvent& message, AppleEvent& /* reply */)
  304. {
  305.     // Get the new position
  306.     DescType    returnedType;
  307.     Point        thePos;
  308.     Size        actualSize;
  309.     FailOSErr(AEGetParamPtr(&message, keyAETheData, typeQDPoint, &returnedType,
  310.                             (Ptr) &thePos, sizeof(thePos), &actualSize));
  311.  
  312.     MAppleObject::GotRequiredParameters(message);
  313.  
  314.     // the point is for the structure region, and is in global coordinates
  315.     // MoveWindow applies to the content region, so we have to massage a little
  316.     // the massage is specific to the type of window we are using
  317.     thePos.v += 19;
  318.     thePos.h++;
  319.  
  320.     // myPoint is now adjusted for the content region
  321.     MoveWindow(fDocument->GetDocWindow(), thePos.h, thePos.v, false);
  322. }
  323.  
  324.  
  325. //--------------------------------------------------------------------------------
  326. // TWindowBounds
  327. //--------------------------------------------------------------------------------
  328.  
  329. class TWindowBounds : public MAppleObject
  330. {
  331. public:
  332.     TWindowBounds(TEDocument* itsDocument);
  333.  
  334.     virtual void DoAppleEvent(const AppleEvent& message, AppleEvent& reply, long refCon);
  335.     virtual DescType GetAppleClass() const;
  336.  
  337.     virtual void DoAppleGetData(const AppleEvent& message, AppleEvent& reply);
  338.     virtual void DoAppleSetData(const AppleEvent& message, AppleEvent& reply);
  339. private:
  340.     TWindowBounds();
  341.  
  342.     TEDocument*    fDocument;
  343. };
  344.  
  345.  
  346. TWindowBounds::TWindowBounds(TEDocument* itsDocument)
  347. {
  348.     fDocument = itsDocument;
  349. }
  350.  
  351.  
  352. void TWindowBounds::DoAppleEvent(const AppleEvent& message, AppleEvent& reply, long refCon)
  353. {
  354.     switch (refCon)
  355.     {
  356.     case cSetData:
  357.         this->DoAppleSetData(message, reply);
  358.         break;
  359.     case cGetData:
  360.         this->DoAppleGetData(message, reply);
  361.         break;
  362.     default:
  363.         MAppleObject::DoAppleEvent(message, reply, refCon);
  364.         break;
  365.     }
  366. }
  367.  
  368.  
  369. DescType TWindowBounds::GetAppleClass() const
  370. {
  371.     return cQDRectangle;
  372. }
  373.  
  374.  
  375. void TWindowBounds::DoAppleGetData(const AppleEvent& message, AppleEvent& reply)
  376. {
  377.     MAppleObject::GotRequiredParameters(message);
  378.  
  379.     // Get the bounds of the window
  380.     Rect    myBounds = (*WindowPeek(fDocument->GetDocWindow())->strucRgn)->rgnBBox;
  381.  
  382.     // Pack the bounds into a descriptor
  383.     AEDesc    boundsDesc;
  384.     FailOSErr(AECreateDesc(typeQDRectangle, (Ptr) &myBounds, sizeof(myBounds), &boundsDesc));
  385.  
  386.     // package the reply
  387.     OSErr theErr = AEPutParamDesc(&reply, keyDirectObject, &boundsDesc);
  388.  
  389.     // dispose of the descriptor we created and check the reply from
  390.     // packaging the reply
  391.     OSErr ignoreErr = AEDisposeDesc(&boundsDesc);
  392.     FailOSErr(theErr);
  393. }
  394.  
  395.  
  396. void TWindowBounds::DoAppleSetData(const AppleEvent& message, AppleEvent& /* reply */)
  397. {
  398.     // Get the new bounds
  399.     DescType    returnedType;
  400.     Rect        theBounds;
  401.     Size        actualSize;
  402.     FailOSErr(AEGetParamPtr(&message, keyAETheData, typeQDRectangle, &returnedType,
  403.                             (Ptr) &theBounds, sizeof(theBounds), &actualSize));
  404.  
  405.     MAppleObject::GotRequiredParameters(message);
  406.  
  407.     // the rectangle is for the structure region, and is in global coordinates
  408.     // MoveWindow and SizeWindow apply to the content region, so we have to massage a little
  409.     // the massage is specific to the type of window we are using
  410.     theBounds.top += 19;
  411.     theBounds.left++;
  412.     theBounds.bottom -= 2;
  413.     theBounds.right -= 2;
  414.     
  415.     // theBounds is now adjusted for the content region
  416.     MoveWindow(fDocument->GetDocWindow(), theBounds.left, theBounds.top, false);
  417.     SizeWindow(fDocument->GetDocWindow(), theBounds.right - theBounds.left,
  418.                theBounds.bottom - theBounds.top, true);
  419.  
  420.     fDocument->UpdateForNewSelection();
  421.     fDocument->AdjustScrollbars(true);
  422. }
  423.  
  424.  
  425. //--------------------------------------------------------------------------------
  426. // TEditText
  427. //--------------------------------------------------------------------------------
  428.  
  429. class TEditText : public MAppleObject
  430. {
  431. public:
  432.     TEditText(TEDocument* itsDocument, TEHandle itsTE);
  433.  
  434.     virtual void DoAppleEvent(const AppleEvent& message, AppleEvent& reply, long refCon);
  435.     virtual DescType GetAppleClass() const;
  436.  
  437.     virtual void DoAppleGetData(const AppleEvent& message, AppleEvent& reply);
  438.     virtual void DoAppleSetData(const AppleEvent& message, AppleEvent& reply);
  439. private:
  440.     TEditText();
  441.  
  442.     TEDocument*    fDocument;
  443.     TEHandle    fTEHandle;
  444. };
  445.  
  446.  
  447. TEditText::TEditText(TEDocument* itsDocument, TEHandle itsTE)
  448. {
  449.     fDocument = itsDocument;
  450.     fTEHandle = itsTE;
  451. }
  452.  
  453.  
  454. void TEditText::DoAppleEvent(const AppleEvent& message, AppleEvent& reply, long refCon)
  455. {
  456.     switch (refCon)
  457.     {
  458.     case cSetData:
  459.         this->DoAppleSetData(message, reply);
  460.         break;
  461.     case cGetData:
  462.         this->DoAppleGetData(message, reply);
  463.         break;
  464.     default:
  465.         MAppleObject::DoAppleEvent(message, reply, refCon);
  466.         break;
  467.     }
  468. }
  469.  
  470.  
  471. DescType TEditText::GetAppleClass() const
  472. {
  473.     return typeText;
  474. }
  475.  
  476.  
  477. void TEditText::DoAppleGetData(const AppleEvent& message, AppleEvent& reply)
  478. {
  479.     MAppleObject::GotRequiredParameters(message);
  480.  
  481.     // Pack the text into a descriptor
  482.     CharsHandle    theText = TEGetText(fTEHandle);
  483.     AEDesc    textDesc;
  484.     HLock((Handle) theText);
  485.     OSErr theErr = AECreateDesc(typeText, (Ptr) *theText,
  486.                                 GetHandleSize((Handle) theText), &textDesc);
  487.  
  488.     // Unlock the handle and check the error code
  489.     HUnlock((Handle) theText);
  490.     FailOSErr(theErr);
  491.  
  492.     // package the reply
  493.     theErr = AEPutParamDesc(&reply, keyDirectObject, &textDesc);
  494.  
  495.     // dispose of the descriptor we created and check the reply from
  496.     // packaging the reply
  497.     OSErr ignoreErr = AEDisposeDesc(&textDesc);
  498.     FailOSErr(theErr);
  499. }
  500.  
  501.  
  502. void TEditText::DoAppleSetData(const AppleEvent& message, AppleEvent& /* reply */)
  503. {
  504.     AEDesc    textDesc;
  505.     FailOSErr(AEGetParamDesc(&message, keyAETheData, typeText, &textDesc));
  506.  
  507.     MAppleObject::GotRequiredParameters(message);
  508.  
  509.     HLock(textDesc.dataHandle);
  510.     TESetText(*textDesc.dataHandle, GetHandleSize(textDesc.dataHandle), fTEHandle);
  511.     HUnlock(textDesc.dataHandle);
  512.  
  513.     OSErr    ignoreErr = AEDisposeDesc(&textDesc);
  514.  
  515.     HLock((Handle) fTEHandle);
  516.     InvalRect(&(*fTEHandle)->viewRect);
  517.     HUnlock((Handle) fTEHandle);
  518.  
  519.     fDocument->UpdateForNewSelection();
  520.     fDocument->AdjustScrollbars(true);
  521. }
  522.  
  523.  
  524. //--------------------------------------------------------------------------------
  525. // TEDocument
  526. //--------------------------------------------------------------------------------
  527.  
  528. // notice that we pass the resID parameter up to our base class,
  529. // which actually creates the window for us
  530. TEDocument::TEDocument(short resID)    : TDocument(resID, kTEFileType)
  531. {
  532.     Boolean good;
  533.     Rect destRect, viewRect;
  534.  
  535.     good = false;
  536.     SetPort(fDocWindow);
  537.     GetTERect(&viewRect);
  538.     destRect = viewRect;
  539.     destRect.right = destRect.left + kMaxDocWidth;
  540.     fDocTE = TEStylNew(&destRect, &viewRect);
  541.     FailNIL(fDocTE);
  542.  
  543.     // set up TE record
  544.     AdjustViewRect();
  545.     TEAutoView(true, fDocTE);
  546.     fDocClik = (*fDocTE)->clikLoop;
  547.     (*fDocTE)->clikLoop = (ClikLoopProcPtr) ASMCLIKLOOP;
  548.  
  549.     fDocVScroll = fDocHScroll = nil;
  550.  
  551.     // get vertical scrollbar
  552.     TRY
  553.       {
  554.         fDocVScroll = GetNewControl(rVScroll, fDocWindow);
  555.         FailNILResource(fDocVScroll);
  556.         fDocHScroll = GetNewControl(rHScroll, fDocWindow);
  557.         FailNILResource(fDocHScroll);
  558.       }
  559.     RECOVER
  560.       {
  561.         TEDispose(fDocTE);
  562.         if (fDocVScroll)
  563.           delete fDocVScroll;
  564.         if (fDocHScroll)
  565.           delete fDocHScroll;
  566.         FailNewMessage(eNoWindow,gFailMessage,kTEDocErrStrings);
  567.       }
  568.     ENDTRY
  569.  
  570.     TEDocument::UpdateForNewSelection();
  571.  
  572.     AdjustScrollValues(true);
  573.     ShowWindow(fDocWindow);
  574.     SelectWindow(fDocWindow);
  575. }
  576.  
  577. TEDocument::~TEDocument()
  578. {
  579.     HideWindow(fDocWindow);
  580.     if ( fDocTE != nil )
  581.       {
  582.         TEDispose(fDocTE);            // dispose the TEHandle if we got far enough to make one
  583.       }
  584.     if ( fDocVScroll != nil )
  585.       {
  586.         DisposeControl(fDocVScroll);
  587.       }
  588.     if ( fDocHScroll != nil )
  589.       {
  590.         DisposeControl(fDocHScroll);
  591.       }
  592.     // base class destructor will dispose of window
  593. }
  594.  
  595. void TEDocument::DoZoom(short partCode)
  596. {
  597.     Rect tRect;
  598.  
  599.     tRect = fDocWindow->portRect;
  600.     EraseRect(&tRect);
  601.     ZoomWindow(fDocWindow, partCode, fDocWindow == FrontWindow());
  602.     AdjustScrollbars(true);        // adjust, redraw anyway
  603.     AdjustTE();
  604.     InvalRect(&tRect);            // invalidate the whole content
  605.     // the scrollbars were taken care of by AdjustScrollbars, so validate ’em
  606.     tRect = (*fDocVScroll)->contrlRect;
  607.     ValidRect(&tRect);
  608.     tRect = (*fDocHScroll)->contrlRect;
  609.     ValidRect(&tRect);
  610. }
  611.  
  612. // Called when a mouseDown occurs in the grow box of an active window.
  613.  
  614. void TEDocument::DoGrow(EventRecord* theEvent)
  615. {
  616.     long growResult;
  617.     Rect tRect, tRect2;
  618.  
  619.     tRect = qd.screenBits.bounds;
  620.     tRect.left = kMinDocDim;
  621.     tRect.top = kMinDocDim;
  622.     growResult = GrowWindow(fDocWindow, theEvent->where, &tRect);
  623.     // see if it really changed size
  624.     if ( growResult != 0 )
  625.       {
  626.         tRect = (*fDocTE)->viewRect;
  627.         SizeWindow(fDocWindow, LoWord(growResult), HiWord(growResult), true);
  628.         AdjustScrollbars(true);
  629.         AdjustTE();
  630.         // calculate & validate the region that hasn’t changed so it won’t get redrawn
  631.         // Note: we copy rectangles so that we don't take address of object fields.
  632.         tRect2 = (*fDocTE)->viewRect;
  633.         (void) SectRect(&tRect, &tRect2, &tRect);
  634.         tRect2 = fDocWindow->portRect; InvalRect(&tRect2);
  635.         ValidRect(&tRect);
  636.         tRect2 = (*fDocVScroll)->contrlRect; ValidRect(&tRect2);
  637.         tRect2 = (*fDocHScroll)->contrlRect; ValidRect(&tRect2);
  638.       }
  639. }
  640.  
  641. void TEDocument::DoContent(EventRecord* theEvent)
  642. {
  643.     Point mouse;
  644.     ControlHandle control;
  645.     short part, value;
  646.     Boolean shiftDown;
  647.     Rect teRect;
  648.  
  649.     SetPort(fDocWindow);
  650.     mouse = theEvent->where;                            // get the click position
  651.     GlobalToLocal(&mouse);
  652.     GetTERect(&teRect);
  653.     if ( PtInRect(mouse, &teRect) )
  654.       {
  655.         // see if we need to extend the selection
  656.         shiftDown = (theEvent->modifiers & shiftKey) != 0;    // extend if Shift is down
  657.         TEClick(mouse, shiftDown, fDocTE);
  658.         UpdateForNewSelection();
  659.       }
  660.     else
  661.       {
  662.         part = FindControl(mouse, fDocWindow, &control);
  663.         switch ( part )
  664.           {
  665.             case 0:
  666.                 // do nothing if not in a control
  667.                 break;
  668.             case inThumb:
  669.                 value = GetCtlValue(control);
  670.                 part = TrackControl(control, mouse, nil);
  671.                 if ( part != 0 )
  672.                   {
  673.                     value -= GetCtlValue(control);
  674.                     // value now has CHANGE in value; if value changed, scroll
  675.                     if ( value != 0 )
  676.                         if ( control == fDocVScroll )
  677.                             TEScroll(0, value * (*fDocTE)->lineHeight, fDocTE);
  678.                         else TEScroll(value, 0, fDocTE);
  679.                   }
  680.                 break;
  681.             default:                        // they clicked in an arrow, so track & scroll
  682.                 if ( control == fDocVScroll )
  683.                     value = TrackControl(control, mouse, (ProcPtr) VActionProc);
  684.                 else value = TrackControl(control, mouse, (ProcPtr) HActionProc);
  685.                 break;
  686.           }
  687.       }
  688. }
  689.  
  690. void TEDocument::DoKeyDown(EventRecord* theEvent)
  691. {
  692.     char key;
  693.  
  694.     if (theEvent->modifiers & cmdKey)    // don't process command characters
  695.       return;
  696.     key = (char) (theEvent->message & charCodeMask);
  697.     // we have a char. for our window; see if we are still below TextEdit’s
  698.     // limit for the number of characters
  699.     if ((key != kDelChar) &&
  700.         ((*fDocTE)->teLength - ((*fDocTE)->selEnd - (*fDocTE)->selStart) + 1 >= kMaxTELength) )
  701.       Failure(eExceedChar,kTEDocErrStrings);
  702.  
  703.     TEKey(key, fDocTE);
  704.     UpdateForNewSelection();
  705.     AdjustScrollbars(false);
  706.     AdjustTE();
  707.     fDirty = true;
  708. }
  709.  
  710. void TEDocument::DoActivate(Boolean becomingActive)
  711. {
  712.     if ( becomingActive )
  713.       {
  714.         RgnHandle    tempRgn;
  715.         RgnHandle    clipRgn;
  716.         Rect        growRect;
  717.         Rect        tRect;
  718.  
  719.         // since we don’t want TEActivate to draw a selection in an area where
  720.         // we’re going to erase and redraw, we’ll clip out the update region
  721.         // before calling it.
  722.         tempRgn = NewRgn();
  723.         clipRgn = NewRgn();
  724.         // save old update region
  725.         CopyRgn(((WindowPeek) fDocWindow)->updateRgn, tempRgn);
  726.         // put it in local coords
  727.         OffsetRgn(tempRgn, fDocWindow->portBits.bounds.left, fDocWindow->portBits.bounds.top);
  728.         GetClip(clipRgn);
  729.         // subtract updateRgn from clipRgn
  730.         DiffRgn(clipRgn, tempRgn, tempRgn);
  731.         // make it the new clipRgn
  732.         SetClip(tempRgn);
  733.         TEActivate(fDocTE);
  734.         // restore the full-blown clipRgn
  735.         SetClip(clipRgn);
  736.         // get rid of temp regions
  737.         DisposeRgn(tempRgn);
  738.         DisposeRgn(clipRgn);
  739.  
  740.         // the controls must be redrawn on activation:
  741.         (*fDocVScroll)->contrlVis = kControlVisible;
  742.         (*fDocHScroll)->contrlVis = kControlVisible;
  743.         // copy rectangles to avoid unsafe object field references!
  744.         tRect = (*fDocVScroll)->contrlRect; InvalRect(&tRect);
  745.         tRect = (*fDocHScroll)->contrlRect; InvalRect(&tRect);
  746.         // the growbox needs to be redrawn on activation:
  747.         growRect = fDocWindow->portRect;
  748.         // adjust for the scrollbars
  749.         growRect.top = growRect.bottom - kScrollbarAdjust;
  750.         growRect.left = growRect.right - kScrollbarAdjust;
  751.         InvalRect(&growRect);
  752.       }
  753.     else
  754.       {
  755.         TEDeactivate(fDocTE);
  756.         // the controls must be hidden on deactivation:
  757.         HideControl(fDocVScroll);
  758.         HideControl(fDocHScroll);
  759.         // we draw grow icon immediately, since we deactivate controls
  760.         // immediately, and the update delay looks funny
  761.         DrawGrowIcon(fDocWindow);
  762.       }
  763. }
  764.  
  765. void TEDocument::DoUpdate()
  766. {
  767.     BeginUpdate(fDocWindow);                // this sets up the visRgn
  768.     if ( ! EmptyRgn(fDocWindow->visRgn) )    // draw if updating needs to be done
  769.       {
  770.         DrawWindow();
  771.       }
  772.     EndUpdate(fDocWindow);
  773. }
  774.  
  775. // calculate how much idle time we need
  776.  
  777. unsigned long TEDocument::CalcIdle()
  778. {
  779.     if (HaveSelection())
  780.       return GetCaretTime();
  781.     else return kMaxSleepTime;    // if we don't have a selection, we don't need to idle
  782. }
  783.  
  784. // This is called whenever we get a null event et al.
  785. // It takes care of necessary periodic actions. For this program,
  786. // it calls TEIdle.
  787.  
  788. void TEDocument::DoIdle()
  789. {
  790.     TEIdle(fDocTE);
  791. } // DoIdle
  792.  
  793. // Draw the contents of an application window.
  794.  
  795. void TEDocument::DrawWindow()
  796. {
  797.     Rect tRect;
  798.  
  799.     SetPort(fDocWindow);
  800.     tRect = fDocWindow->portRect;
  801.     EraseRect(&tRect);
  802.     TEUpdate(&tRect, fDocTE);
  803.     DrawControls(fDocWindow);
  804.     DrawGrowIcon(fDocWindow);
  805. } // DrawWindow
  806.  
  807. // Return a rectangle that is inset from the portRect by the size of
  808. // the scrollbars and a little extra margin.
  809.  
  810. void TEDocument::GetTERect(Rect* teRect)
  811. {
  812.     *teRect = fDocWindow->portRect;
  813.     InsetRect(teRect, kTextMargin, kTextMargin);            // adjust for margin
  814.     teRect->bottom = teRect->bottom - kScrollbarAdjust;    // and for the scrollbars
  815.     teRect->right = teRect->right - kScrollbarAdjust;
  816. } // GetTERect
  817.  
  818. // setup a region which contains the visible text
  819.  
  820. void TEDocument::GetVisTERgn(RgnHandle rgn)
  821. {
  822.     Rect teRect;
  823.  
  824.     teRect = (*fDocTE)->viewRect;    // get a local copy of viewRect
  825.     SetPort(fDocWindow);            // make sure we have right port
  826.     LocalToGlobal((Point*) &teRect.top);
  827.     LocalToGlobal((Point*) &teRect.bottom);
  828.     RectRgn(rgn, &teRect);
  829.     // we temporarily change the port’s origin to “globalfy” the visRgn
  830.     SetOrigin(-(fDocWindow->portBits.bounds.left),
  831.               -(fDocWindow->portBits.bounds.top));
  832.     SectRgn(rgn, fDocWindow->visRgn, rgn);
  833.     SetOrigin(0, 0);
  834. } // GetTERgn
  835.  
  836. void TEDocument::ReadFromFile(short refNum)
  837. {
  838.     long curPos, size;
  839.     Handle h;
  840.  
  841.     // determine how much data is available to read
  842.     FailOSErr(GetFPos(refNum,&curPos));
  843.     FailOSErr(GetEOF(refNum,&size));
  844.     size -= curPos;
  845.  
  846.     // check for size > 32K
  847.     if (size > kMaxTELength)
  848.       Failure(eExceedChar,kTEDocErrStrings);
  849.  
  850.     // allocate a handle to store it in
  851.     h = NewHandle(size);
  852.     FailNIL(h);
  853.  
  854.     TRY
  855.       {
  856.         FailOSErr(FSRead(refNum,&size,*h));
  857.       }
  858.     RECOVER
  859.       {
  860.         DisposHandle(h);
  861.       }
  862.     ENDTRY
  863.  
  864.     // now make the text the current text
  865.     SetPort(fDocWindow);
  866.     HLock(h);
  867.     TESetText(*h,size,fDocTE);
  868.     DisposHandle(h);
  869.  
  870.     // make sure everything is up to date
  871.     Rect tRect = (*fDocTE)->viewRect;
  872.     InvalRect(&tRect);
  873.     AdjustTE();
  874.     UpdateForNewSelection();
  875.     AdjustScrollbars(false);
  876. }
  877.  
  878. void TEDocument::WriteToFile(short refNum)
  879. {
  880.     Handle h;
  881.     long size;
  882.  
  883.     // get COPY of TEHandle - doesn't alloc memory
  884.     h = (Handle) TEGetText(fDocTE);
  885.     size = GetHandleSize(h);
  886.     FailOSErr(FSWrite(refNum,&size,*h));
  887. }
  888.  
  889. // Return boolean value indicating that there is or is not a
  890. // selection in the document
  891.  
  892. Boolean TEDocument::HaveSelection()
  893. {
  894.     if ( (*fDocTE)->selStart < (*fDocTE)->selEnd )
  895.       return true;
  896.     else return false;
  897. }
  898.  
  899. // Update the TERec's view rect so that it is the greatest multiple of
  900. // the lineHeight that still fits in the old viewRect.
  901.  
  902. void TEDocument::AdjustViewRect()
  903. {
  904.     TEPtr te;
  905.  
  906.     te = *fDocTE;
  907.     te->viewRect.bottom = (((te->viewRect.bottom - te->viewRect.top) / te->lineHeight)
  908.                             * te->lineHeight) + te->viewRect.top;
  909. } // AdjustViewRect
  910.  
  911. // Scroll the TERec around to match up to the potentially updated scrollbar
  912. // values. This is really useful when the window has been resized such that the
  913. // scrollbars became inactive but the TERec was already scrolled.
  914.  
  915. void TEDocument::AdjustTE()
  916. {
  917.     TEPtr te;
  918.  
  919.     te = *fDocTE;
  920.     TEScroll((te->viewRect.left - te->destRect.left) - GetCtlValue(fDocHScroll),
  921.              (te->viewRect.top - te->destRect.top) -
  922.                  (GetCtlValue(fDocVScroll) * te->lineHeight),
  923.              fDocTE);
  924. } // AdjustTE
  925.  
  926. // Re-calculate the position and size of the viewRect and the scrollbars.
  927. // kScrollTweek compensates for off-by-one requirements of the scrollbars
  928. // to have borders coincide with the growbox.
  929.  
  930. void TEDocument::AdjustScrollSizes()
  931. {
  932.     Rect teRect;
  933.  
  934.     GetTERect(&teRect);
  935.     (*fDocTE)->viewRect = teRect;
  936.     AdjustViewRect();
  937.     MoveControl(fDocVScroll, fDocWindow->portRect.right - kScrollbarAdjust, -1);
  938.     SizeControl(fDocVScroll, kScrollbarWidth,
  939.                 fDocWindow->portRect.bottom - fDocWindow->portRect.top -
  940.                     kGrowboxAdjust + kScrollTweek);
  941.     MoveControl(fDocHScroll, -1, fDocWindow->portRect.bottom - kScrollbarAdjust);
  942.     SizeControl(fDocHScroll,
  943.                 fDocWindow->portRect.right - fDocWindow->portRect.left -
  944.                     kGrowboxAdjust + kScrollTweek,
  945.                 kScrollbarWidth);
  946. } // AdjustScrollSizes
  947.  
  948. // Turn off the controls by jamming a zero into their contrlVis fields (HideControl erases them
  949. // and we don't want that). If the controls are to be resized as well, call the procedure to do that,
  950. // then call the procedure to adjust the maximum and current values. Finally re-enable the controls
  951. // by jamming a $FF in their contrlVis fields (ShowControl re-draws the control, which may not be
  952. // necessary).
  953.  
  954. void TEDocument::AdjustScrollbars(Boolean needsResize)
  955. {
  956.     // First, turn visibility of scrollbars off so we won’t get unwanted redrawing
  957.     (*fDocVScroll)->contrlVis = 0;
  958.     (*fDocHScroll)->contrlVis = 0;
  959.     if ( needsResize )
  960.       AdjustScrollSizes();
  961.     AdjustScrollValues(needsResize);
  962.     // Now, restore visibility in case we never had to draw during adjustment
  963.     (*fDocVScroll)->contrlVis = 0xff;
  964.     (*fDocHScroll)->contrlVis = 0xff;
  965. } // AdjustScrollbars
  966.  
  967. // Calculate the new control maximum value and current value, whether it is the horizontal or
  968. // vertical scrollbar. The vertical max is calculated by comparing the number of lines to the
  969. // vertical size of the viewRect. The horizontal max is calculated by comparing the maximum document
  970. // width to the width of the viewRect. The current values are set by comparing the offset between
  971. // the view and destination rects. If necessary, redraw the control by calling ShowControl.
  972.  
  973. void TEDocument::AdjustHV(Boolean isVert,Boolean mustRedraw)
  974. {
  975.     short value, lines, max;
  976.     short oldValue, oldMax;
  977.     TEPtr te;
  978.     ControlHandle control;
  979.  
  980.     if (isVert)
  981.       control = fDocVScroll;
  982.     else control = fDocHScroll;
  983.     oldValue = GetCtlValue(control);
  984.     oldMax = GetCtlMax(control);
  985.     te = *fDocTE;                            // point to TERec for convenience
  986.     if ( isVert )
  987.       {
  988.         lines = te->nLines;
  989.         // since nLines isn’t right if the last character is a return, check for that case
  990.         if ( *(*te->hText + te->teLength - 1) == kCrChar )
  991.           lines += 1;
  992.         max = lines - ((te->viewRect.bottom - te->viewRect.top) /
  993.                        te->lineHeight);
  994.       }
  995.     else max = kMaxDocWidth - (te->viewRect.right - te->viewRect.left);
  996.  
  997.     if ( max < 0 )
  998.       max = 0;
  999.     SetCtlMax(control, max);
  1000.  
  1001.     // Must deref. after SetCtlMax since, technically, it could draw and therefore move
  1002.     // memory. This is why we don’t just do it once at the beginning.
  1003.     te = *fDocTE;
  1004.     if ( isVert )
  1005.       value = (te->viewRect.top - te->destRect.top) / te->lineHeight;
  1006.     else value = te->viewRect.left - te->destRect.left;
  1007.  
  1008.     if ( value < 0 )
  1009.       value = 0;
  1010.     else if ( value >  max )
  1011.       value = max;
  1012.  
  1013.     SetCtlValue(control, value);
  1014.     // now redraw the control if asked to or if a setting changed
  1015.     if ( mustRedraw || (max != oldMax) || (value != oldValue) )
  1016.         ShowControl(control);
  1017. } // AdjustHV
  1018.  
  1019. // Simply call the common adjust routine for the vertical and horizontal scrollbars.
  1020.  
  1021. void TEDocument::AdjustScrollValues(Boolean mustRedraw)
  1022. {
  1023.     AdjustHV(true, mustRedraw);
  1024.     AdjustHV(false, mustRedraw);
  1025. } // AdjustScrollValues
  1026.  
  1027. ClikLoopProcPtr TEDocument::GetClikLoop()
  1028. {
  1029.     return fDocClik;
  1030. }
  1031.  
  1032. TEHandle TEDocument::GetTEHandle()
  1033. {
  1034.     return fDocTE;
  1035. }
  1036.  
  1037. void TEDocument::DoCut()
  1038. {
  1039.     long total, contig;
  1040.  
  1041.     if (ZeroScrap() == noErr)
  1042.       {
  1043.         PurgeSpace(&total, &contig);
  1044.         if ((*fDocTE)->selEnd - (*fDocTE)->selStart + kTESlop > contig)
  1045.           Failure(eNoSpaceCut,kTEDocErrStrings);
  1046.  
  1047.         TECut(fDocTE);
  1048.         fDirty = true;
  1049.         if (TEToScrap() != noErr)
  1050.           {
  1051.             (void) ZeroScrap();
  1052.             Failure(eNoCut,kTEDocErrStrings);
  1053.           }
  1054.       }
  1055.     UpdateForNewSelection();
  1056.     AdjustScrollbars(false);
  1057.     AdjustTE();
  1058. }
  1059.  
  1060. void TEDocument::DoCopy()
  1061. {
  1062.     if (ZeroScrap() == noErr)
  1063.       {
  1064.         TECopy(fDocTE);                // after copying, export the TE scrap
  1065.         if (TEToScrap() != noErr)
  1066.           {
  1067.             ZeroScrap();
  1068.             Failure(eNoCopy,kTEDocErrStrings);
  1069.           }
  1070.       }
  1071.     UpdateForNewSelection();
  1072.     AdjustScrollbars(false);
  1073.     AdjustTE();
  1074. }
  1075.  
  1076. void TEDocument::DoPaste()
  1077. {
  1078.     Handle aHandle;
  1079.     long oldSize, newSize;
  1080.     OSErr saveErr;
  1081.  
  1082.     if ( TEGetScrapLen() + ((*fDocTE)->teLength -
  1083.          ((*fDocTE)->selEnd - (*fDocTE)->selStart)) > kMaxTELength )
  1084.       Failure(eExceedPaste,kTEDocErrStrings);
  1085.  
  1086.     aHandle = (Handle) TEGetText(fDocTE);
  1087.     oldSize = GetHandleSize(aHandle);
  1088.     newSize = oldSize + TEGetScrapLen() + kTESlop;
  1089.  
  1090.     // preflight the growth of the text handle for textedit,
  1091.     // since it will crash if it doesn't have enough memory
  1092.     SetHandleSize(aHandle, newSize);
  1093.     saveErr = MemError();
  1094.     SetHandleSize(aHandle, oldSize);
  1095.     if (saveErr != noErr)
  1096.       Failure(eNoSpacePaste,kTEDocErrStrings);
  1097.  
  1098.     TEStylPaste(fDocTE);
  1099.     fDirty = true;
  1100.  
  1101.     UpdateForNewSelection();
  1102.     AdjustScrollbars(false);
  1103.     AdjustTE();
  1104. }
  1105.  
  1106. void TEDocument::DoClear()
  1107. {
  1108.     TEDelete(fDocTE);
  1109.     fDirty = true;
  1110.     UpdateForNewSelection();
  1111.     AdjustScrollbars(false);
  1112.     AdjustTE();
  1113. }
  1114.  
  1115. void TEDocument::DoSelectAll()
  1116. {
  1117.     long selSize = (*fDocTE)->teLength;
  1118.     TESetSelect(0,selSize,fDocTE);
  1119.     UpdateForNewSelection();
  1120. }
  1121.  
  1122.  
  1123. void TEDocument::SetFontName(Str255 fontName)
  1124. {
  1125.     short    fontID;
  1126.  
  1127.     GetFNum(fontName, &fontID);
  1128.     SetFont(fontID);
  1129. }
  1130.  
  1131. void TEDocument::SetFont(short fontID)
  1132. {
  1133.     fTxStyle.tsFont = fontID;
  1134.     TESetStyle(doFont, &fTxStyle, true, fDocTE);
  1135.     fDirty = true;
  1136.     UpdateForNewSelection();
  1137.     AdjustScrollbars(false);
  1138. }
  1139.  
  1140. void TEDocument::SetFontSize(short fontSize)
  1141. {
  1142.     fTxStyle.tsSize = fontSize;
  1143.     TESetStyle(doSize, &fTxStyle, true, fDocTE);
  1144.     fDirty = true;
  1145.     UpdateForNewSelection();
  1146.     AdjustScrollbars(false);
  1147. }
  1148.  
  1149. short TEDocument::GetSelectionFontSize()
  1150. {
  1151.     return (fSelSizeContinuous ? fTxStyle.tsSize : -1);
  1152. }
  1153.  
  1154. short TEDocument::GetSelectionFont()
  1155. {
  1156.     return (fSelFontContinuous ? fTxStyle.tsFont : -1);
  1157. }
  1158.  
  1159. void TEDocument::SetFaceAttributes(short attributes, Boolean on)
  1160. {
  1161.     if (on)
  1162.         fTxStyle.tsFace |= attributes;
  1163.     else
  1164.         fTxStyle.tsFace &= ~attributes;
  1165.  
  1166.     TESetStyle(doFace, &fTxStyle, true, fDocTE);
  1167.     fDirty = true;
  1168.     UpdateForNewSelection();
  1169.     AdjustScrollbars(false);
  1170. }
  1171.  
  1172. void TEDocument::SetPlain()
  1173. {
  1174.     fTxStyle.tsFace = normal;
  1175.  
  1176.     TESetStyle(doFace, &fTxStyle, true, fDocTE);
  1177.     fDirty = true;
  1178.     UpdateForNewSelection();
  1179.     AdjustScrollbars(false);
  1180. }
  1181.  
  1182. void TEDocument::SetUnderline(Boolean on)
  1183. {
  1184.     SetFaceAttributes(underline, on);
  1185. }
  1186.  
  1187. void TEDocument::SetOutline(Boolean on)
  1188. {
  1189.     SetFaceAttributes(outline, on);
  1190. }
  1191.  
  1192. void TEDocument::SetShadow(Boolean on)
  1193. {
  1194.     SetFaceAttributes(shadow, on);
  1195. }
  1196.  
  1197. void TEDocument::SetItalic(Boolean on)
  1198. {
  1199.     SetFaceAttributes(italic, on);
  1200. }
  1201.  
  1202. void TEDocument::SetBold(Boolean on)
  1203. {
  1204.     SetFaceAttributes(bold, on);
  1205. }
  1206.  
  1207. Boolean TEDocument::GetFaceAttributes(short attributes)
  1208. {
  1209.     return (fSelFaceContinuous  &&  (fTxStyle.tsFace & attributes) == attributes);
  1210. }
  1211.  
  1212. Boolean TEDocument::SelectionIsPlain()
  1213. {
  1214.     return (fSelFaceContinuous  &&  fTxStyle.tsFace == normal);
  1215. }
  1216.  
  1217. Boolean TEDocument::SelectionIsUnderline()
  1218. {
  1219.     return GetFaceAttributes(underline);
  1220. }
  1221.  
  1222. Boolean TEDocument::SelectionIsOutline()
  1223. {
  1224.     return GetFaceAttributes(outline);
  1225. }
  1226.  
  1227. Boolean TEDocument::SelectionIsShadow()
  1228. {
  1229.     return GetFaceAttributes(shadow);
  1230. }
  1231.  
  1232. Boolean TEDocument::SelectionIsItalic()
  1233. {
  1234.     return GetFaceAttributes(italic);
  1235. }
  1236.  
  1237. Boolean TEDocument::SelectionIsBold()
  1238. {
  1239.     return GetFaceAttributes(bold);
  1240. }
  1241.  
  1242. void TEDocument::UpdateForNewSelection()
  1243. {
  1244.     // make sure we catch all the text attributes
  1245.     short    mode = doAll;
  1246.     fSelFontContinuous = TEContinuousStyle(&mode, &fTxStyle, fDocTE);
  1247.  
  1248.     // then, ask for each type in which we are interested individually
  1249.     mode = doFont;
  1250.     fSelFontContinuous = TEContinuousStyle(&mode, &fTxStyle, fDocTE);
  1251.  
  1252.     mode = doFace;
  1253.     fSelFaceContinuous = TEContinuousStyle(&mode, &fTxStyle, fDocTE);
  1254.  
  1255.     mode = doSize;
  1256.     fSelSizeContinuous = TEContinuousStyle(&mode, &fTxStyle, fDocTE);
  1257. }
  1258.  
  1259.  
  1260. /*
  1261.     Routines used by this class, which don't belong to the class since we use
  1262.     them as toolbox filter routines, and you cannot pass class methods as ProcPtrs.
  1263. */
  1264.  
  1265. // Common algorithm for pinning the value of a control. It returns the actual amount
  1266. // the value of the control changed.
  1267.  
  1268. void CommonAction(ControlHandle control,short* amount)
  1269. {
  1270.     short        value, max;
  1271.  
  1272.     value = GetCtlValue(control);
  1273.     max = GetCtlMax(control);
  1274.     *amount = value - *amount;
  1275.     if ( *amount <= 0 )
  1276.         *amount = 0;
  1277.     else if ( *amount >= max )
  1278.         *amount = max;
  1279.     SetCtlValue(control, *amount);
  1280.     *amount = value - *amount;
  1281. } // CommonAction
  1282.  
  1283.  
  1284. // Determines how much to change the value of the vertical scrollbar by and how
  1285. // much to scroll the TE record.
  1286.  
  1287. pascal void TEDocument::VActionProc(ControlHandle control,short part)
  1288. {
  1289.     short        amount;
  1290.     WindowPtr    window;
  1291.     TEPtr        te;
  1292.     TEDocument* doc;
  1293.  
  1294.     if ( part != 0 )
  1295.       {
  1296.         window = (*control)->contrlOwner;
  1297.         doc = (TEDocument*) (TESample::GetTEApplication()->DocList())->FindDoc(window);
  1298.         te = *(doc->GetTEHandle());
  1299.         switch ( part )
  1300.           {
  1301.             case inUpButton:
  1302.             case inDownButton:        // one line
  1303.                 amount = 1;
  1304.                 break;
  1305.             case inPageUp:            // one page
  1306.             case inPageDown:
  1307.                 amount = (te->viewRect.bottom - te->viewRect.top) / te->lineHeight;
  1308.                 break;
  1309.           }
  1310.         if ( (part == inDownButton) || (part == inPageDown) )
  1311.             amount = -amount;        // reverse direction for a downer
  1312.         CommonAction(control, &amount);
  1313.         if ( amount != 0 )
  1314.             TEScroll(0, amount * te->lineHeight, doc->GetTEHandle());
  1315.       }
  1316. } // VActionProc
  1317.  
  1318. // Determines how much to change the value of the horizontal scrollbar by and how
  1319. // much to scroll the TE record.
  1320.  
  1321. pascal void TEDocument::HActionProc(ControlHandle control,short part)
  1322. {
  1323.     short        amount;
  1324.     WindowPtr    window;
  1325.     TEPtr        te;
  1326.     TEDocument* doc;
  1327.  
  1328.     if ( part != 0 )
  1329.       {
  1330.         window = (*control)->contrlOwner;
  1331.         doc = (TEDocument*) (TESample::GetTEApplication()->DocList())->FindDoc(window);
  1332.         te = *(doc->GetTEHandle());
  1333.         switch ( part )
  1334.           {
  1335.             case inUpButton:
  1336.             case inDownButton:        // a few pixels
  1337.                 amount = 4;
  1338.                 break;
  1339.             case inPageUp:            // a page
  1340.             case inPageDown:
  1341.                 amount = te->viewRect.right - te->viewRect.left;
  1342.                 break;
  1343.           }
  1344.         if ( (part == inDownButton) || (part == inPageDown) )
  1345.             amount = -amount;        // reverse direction
  1346.         CommonAction(control, &amount);
  1347.         if ( amount != 0 )
  1348.             TEScroll(amount, 0, doc->GetTEHandle());
  1349.       }
  1350. } // VActionProc
  1351.  
  1352. // Gets called from our assembly language routine, AsmClikLoop, which is in
  1353. // turn called by the TEClick toolbox routine. Saves the windows clip region,
  1354. // sets it to the portRect, adjusts the scrollbar values to match the TE scroll
  1355. // amount, then restores the clip region.
  1356.  
  1357. pascal void PascalClikLoop()
  1358. {
  1359.     RgnHandle    region;
  1360.     WindowPtr wind;
  1361.     TEDocument* doc;
  1362.  
  1363.     wind = FrontWindow();
  1364.     doc = (TEDocument*) (TESample::GetTEApplication()->DocList())->FindDoc(wind);
  1365.     region = NewRgn();
  1366.     GetClip(region);    // save clip
  1367.     ClipRect(&wind->portRect);
  1368.     doc->AdjustScrollValues(false);
  1369.     SetClip(region);    // restore clip
  1370.     DisposeRgn(region);
  1371. } // PascalClikLoop
  1372.  
  1373. // Gets called from our assembly language routine, AsmClikLoop, which is in
  1374. // turn called by the TEClick toolbox routine. It returns the address of the
  1375. // default clikLoop routine that was put into the TERec by TEAutoView to
  1376. // AsmClikLoop so that it can call it.
  1377.  
  1378. pascal ClikLoopProcPtr GetOldClikLoop()
  1379. {
  1380.     TEDocument* doc;
  1381.  
  1382.     doc = (TEDocument*) (TESample::GetTEApplication()->DocList())->FindDoc(FrontWindow());
  1383.     if (doc == nil)
  1384.       return nil;
  1385.     return doc->GetClikLoop();
  1386. } // GetOldClikLoop
  1387.  
  1388.  
  1389.  
  1390. DescType TEDocument::GetAppleClass() const
  1391. {
  1392.     return cWindow;
  1393. }
  1394.  
  1395.  
  1396. long TEDocument::CountContainedObjects(DescType ofType)
  1397. {
  1398.     return MAppleObject::CountContainedObjects(ofType);
  1399. }
  1400.  
  1401.  
  1402. void TEDocument::DoAppleEvent(const AppleEvent& message, AppleEvent& reply, long refCon)
  1403. {
  1404.     switch (refCon)
  1405.     {
  1406.     case cSave:
  1407.         this->DoAppleSave(message, reply);
  1408.         break;
  1409.     case cClose:
  1410.         this->DoAppleClose(message, reply);
  1411.         break;
  1412.     default:
  1413.         MAppleObject::DoAppleEvent(message, reply, refCon);
  1414.         break;
  1415.     }
  1416. }
  1417.  
  1418.  
  1419. MAppleObject* TEDocument::GetContainedObject(DescType desiredType, DescType keyForm,
  1420.                                            const AEDesc& keyData, Boolean& needDisposal)
  1421. {
  1422.     MAppleObject*    result = nil;
  1423.  
  1424.     switch (keyForm)
  1425.     {
  1426.     case formPropertyID:
  1427.         result = this->GetAppleProperty(keyForm, keyData, needDisposal);
  1428.         break;
  1429.     }
  1430.  
  1431.     if (result == nil)
  1432.         result = MAppleObject::GetContainedObject(desiredType, keyForm, keyData, needDisposal);
  1433.  
  1434.     return result;
  1435. }
  1436.  
  1437.  
  1438. MAppleObject* TEDocument::GetAppleProperty(DescType keyForm, const AEDesc& keyData,
  1439.                                            Boolean& needDisposal)
  1440. {
  1441.     MAppleObject*    result = nil;
  1442.  
  1443.     // Our property accessors only work on formPropertyID
  1444.     if (keyForm != formPropertyID)
  1445.         FailOSErr(errAEWrongDataType);
  1446.  
  1447.     DescType    whichProperty;
  1448.     if (keyData.descriptorType == typeType)
  1449.         whichProperty = *(DescType*)*keyData.dataHandle;
  1450.     else
  1451.     {
  1452.         AEDesc    whichPropertyDesc;
  1453.         FailOSErr(AECoerceDesc(&keyData, typeType, &whichPropertyDesc));
  1454.         whichProperty = *(DescType*)*whichPropertyDesc.dataHandle;
  1455.         OSErr ignoreErr = AEDisposeDesc(&whichPropertyDesc);
  1456.     }
  1457.  
  1458.     switch (whichProperty)
  1459.     {
  1460.     case pBounds:
  1461.         result = new TWindowBounds(this);
  1462.         FailNIL(result);
  1463.         needDisposal = true;
  1464.         break;
  1465.     case pPosition:
  1466.         result = new TWindowPosition(this);
  1467.         FailNIL(result);
  1468.         needDisposal = true;
  1469.         break;
  1470.     case pName:
  1471.         result = new TWindowName(this);
  1472.         FailNIL(result);
  1473.         needDisposal = true;
  1474.         break;
  1475.     case pText:
  1476.         result = new TEditText(this, fDocTE);
  1477.         FailNIL(result);
  1478.         needDisposal = true;
  1479.         break;
  1480.     }
  1481.  
  1482.     return result;
  1483. }
  1484.  
  1485.  
  1486. Boolean TEDocument::CompareAppleObjects(DescType operation, const MAppleObject& toWhat)
  1487. {
  1488.     return MAppleObject::CompareAppleObjects(operation, toWhat);
  1489. }
  1490.  
  1491.  
  1492. void TEDocument::DoAppleSave(const AppleEvent& message, AppleEvent& /* reply */)
  1493. {
  1494.     DescType    returnedType;
  1495.     Size        actualSize;
  1496.     FSSpec        myFSSpec;
  1497.  
  1498.     OSErr    tempErr = AEGetParamPtr(&message, keyAEDestination,
  1499.                                     typeFSS, &returnedType, (Ptr) &myFSSpec,
  1500.                                     sizeof(myFSSpec), &actualSize);
  1501.     if (tempErr == noErr)
  1502.     {
  1503.         MAppleObject::GotRequiredParameters(message);
  1504.         this->CloseFile();
  1505.         fFile = myFSSpec;
  1506.         this->OpenFile(false, true);
  1507.         this->DoSave();
  1508.     }
  1509.     else if (tempErr != errAEDescNotFound)
  1510.         FailOSErr(tempErr);
  1511.     else
  1512.         MAppleObject::GotRequiredParameters(message);
  1513. }
  1514.  
  1515.  
  1516.  
  1517. void TEDocument::DoAppleClose(const AppleEvent& message, AppleEvent& /* reply */)
  1518. {
  1519.     DescType    saveOpt = kAEYes;    // default to save on close
  1520.  
  1521.     DescType    returnedType;
  1522.     Size        actualSize;
  1523.     OSErr        tempErr = AEGetParamPtr(&message, keyAESaveOptions,
  1524.                                         cEnumeration, &returnedType,
  1525.                                         (Ptr) &saveOpt,
  1526.                                         sizeof(saveOpt), &actualSize);
  1527.     if (tempErr != noErr  &&  tempErr != errAEDescNotFound)
  1528.         FailOSErr(tempErr);
  1529.  
  1530.     if (saveOpt == kAEYes)
  1531.     {
  1532.         FSSpec    myFSSpec;
  1533.         tempErr = AEGetParamPtr(&message, keyAEDestination, typeFSS,
  1534.                                 &returnedType, (Ptr) &myFSSpec, sizeof(myFSSpec),
  1535.                                 &actualSize);
  1536.         if (tempErr == noErr)
  1537.         {
  1538.             MAppleObject::GotRequiredParameters(message);
  1539.             this->CloseFile();
  1540.             fFile = myFSSpec;
  1541.             this->OpenFile(false, true);
  1542.             this->DoSave();
  1543.         }
  1544.         else if (tempErr != errAEDescNotFound)
  1545.             FailOSErr(tempErr);
  1546.         else
  1547.             MAppleObject::GotRequiredParameters(message);
  1548.     }
  1549.  
  1550.     (void) this->DoClose(false, yesResult, false);
  1551.  
  1552.     TApplication::GetApplication()->DocList()->RemoveDoc(this);
  1553.  
  1554.     // We really want ourselves deleted now, but it’s really bad form to delete oneself.
  1555.     // However, this method gets invoked from an AppleEvent, thus we are a token object
  1556.     // and can now set our “disposal flag” to true.
  1557.     TAppleObjectDispatcher::GetDispatcher()->SetTokenObjectDisposal(this, true);
  1558. }
  1559.